﻿#region Includes
using System;
using System.Collections.Generic;

using OpenTK.Input;
#endregion

namespace GingerGL.Input
{
    //------------------------------------------------------------//
    /// <summary>
    /// Key Binding Function
    /// </summary>
    public class KeyBindings
    {
        //--------------------------------------------------------//
        #region Delegates
        public delegate void MouseMoveFunction(MouseMoveEventArgs e);
        #endregion
        //--------------------------------------------------------//
        #region Variables
        static public KeyBindings Instance = new KeyBindings();
        private MouseState mLastMouseState;
        #endregion
        //--------------------------------------------------------//
        #region Properties
        /// <summary>
        /// Gets list of bound keys
        /// </summary>
        public Dictionary<Key, Action> KeyboardBinds { get; private set; }
        /// <summary>
        /// Gets list of bound mouse buttons
        /// </summary>
        public Dictionary<MouseButton, Action> MouseBinds { get; private set; }
        /// <summary>
        /// Gets Mouse Move function
        /// </summary>
        public MouseMoveFunction MouseMove { get; private set; }
        #endregion
        //--------------------------------------------------------//
        #region Constructor
        /// <summary>
        /// Initializes a new instance of object
        /// </summary>
        public KeyBindings()
        {
            this.KeyboardBinds = new Dictionary<Key, Action>();
            this.MouseBinds = new Dictionary<MouseButton,Action>();
        }
        #endregion
        //--------------------------------------------------------//
        #region Functions
        /// <summary>
        /// Bind Keyboard Key to Function
        /// </summary>
        public void Bind(Key key, Action function) { this.KeyboardBinds.Add(key, function); }
        /// <summary>
        /// Bind Mouse Button to Fuction
        /// </summary>
        public void Bind(MouseButton button, Action function) { this.MouseBinds.Add(button, function); }
        /// <summary>
        /// Bind Mouse Move Function
        /// </summary>
        public void Bind(MouseMoveFunction mousemove) { this.MouseMove = mousemove; }
        /// <summary>
        /// Unbind Keyboard Key
        /// </summary>
        public void Unbind(Key key) { this.KeyboardBinds.Remove(key); }
        /// <summary>
        /// Unbind Mouse Button
        /// </summary>
        public void Unbind(MouseButton button) { this.MouseBinds.Remove(button); }
        /// <summary>
        /// Unbind all funtions
        /// </summary>
        public void Unbind()
        {
            this.MouseMove = null;
            this.MouseBinds.Clear();
            this.KeyboardBinds.Clear();
        }
        /// <summary>
        /// Update Bindings and call appropriate functions
        /// </summary>
        public void Update()
        {
            MouseState ms = Mouse.GetState();                                       //get mouse state
            KeyboardState ks = Keyboard.GetState();                                 //get keyboard state
            foreach (KeyValuePair<MouseButton, Action> m in this.MouseBinds)        //run the the mouse binds
            {
                if (ms[m.Key])                                                      //if button is pressed
                    m.Value.Invoke();                                               //execute function
            }
            foreach(KeyValuePair<Key, Action> k in this.KeyboardBinds)              //run through keyboard binds
            {
                if (ks[k.Key])                                                      //if key is pressed
                    k.Value.Invoke();                                               //execute function
            }
            if (mLastMouseState != ms)                                              //have the states changed?
            {
                this.MouseMove.Invoke(                                              //execute mouse move update
                    new MouseMoveEventArgs
                    (
                        ms.X,
                        ms.Y,
                        mLastMouseState.X - ms.X,
                        mLastMouseState.Y - ms.Y)
                    );
                this.mLastMouseState = ms;                                          //update last state
            }
        }
        #endregion
        //--------------------------------------------------------//
    }
    //------------------------------------------------------------//
}
